package com.dylan.shot.common.config;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Created by Dylan on 2017/10/18.
 */
@Component
public class RedisCacheHelper {
    public final static int CACHE_1_MINUTE = 60; //默认缓存时间 1分钟
    public final static int CACHE_5_MINUTE = 5 * 60; //默认缓存时间 1分钟
    public final static int CACHE_30_MINUTE = 30 * 60; //默认缓存时间 1分钟
    public final static int CACHE_1_HOUR = 60 * 60; //默认缓存时间 1小时;
    public final static int CACHE_12_HOURS = 60 * 60 * 12; //默认缓存时间 12小时;
    public final static int CACHE_1_DAY = 60 * 60 * 24; //默认缓存时间 1天
    public final static int CACHE_1_WEEK = 60 * 60 * 24 * 7; //默认缓存时间 1周
    public final static int CACHE_1_MONTH = 60 * 60 * 24 * 30; //默认缓存时间 1月

    /**
     * 默认缓存时间,单位秒
     */
    private final long DEFAULT_EXPIRE_TIME = 2 * CACHE_1_MINUTE;

    /**
     * 缓存单位,秒
     */
    private final TimeUnit EXPIRE_TIME_UNIT = TimeUnit.SECONDS;

    /**
     * RedisObjectMapper不创建为Spring管理的Bean对象,以免覆盖spring-mvc中使用的ObjectMapper对象
     */
    private RedisObjectMapper redisObjectMapper = new RedisObjectMapper();

    @Resource(name = "myRedisTemplate")
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 保存缓存,过期时间使用默认时间
     * @param key KEY
     * @param value 值
     */
    public void setObject(String key, Object value) {
        setObject(key, value, DEFAULT_EXPIRE_TIME);
    }

    /**
     * 保存缓存
     * @param key KEY
     * @param value 值
     * @param expireSeconds 过期时间,单位秒
     */
    public <T> void setObject(String key, T value, long expireSeconds) {
        key = trimKey(key);
        if (value != null) {
            String jsonValue = redisObjectMapper.writeValueAsString(value);
            redisTemplate.opsForValue().set(key, jsonValue);
            // 设置过期时间
            expire(key, expireSeconds);
        }
    }

    /**
     * 获取缓存
     * @param key KEY
     * @param requiredType 需要转换的类型,和保存缓存的类型一致
     * @return 值
     */
    public <T> T getObject(String key, Class<T> requiredType) {
        key = trimKey(key);
        String jsonValue = redisTemplate.opsForValue().get(key);
        if (jsonValue != null) {
            return redisObjectMapper.readValue(jsonValue, requiredType);
        }
        return null;
    }

    /**
     * 根据匹配模式获取KEY列表
     * @param pattern 匹配模式
     * @return KEY列表
     */
    public Set<String> keys(String pattern) {
        return redisTemplate.keys(pattern);
    }

    /**
     * 删除KEY
     * @param key KEY
     */
    public void delete(String key) {
        key = trimKey(key);
        redisTemplate.delete(key);
    }

    /**
     * 设置过期时间,负数为设置常驻缓存
     * @param key KEY
     * @param expireSeconds 过期时间,单位秒
     * @return 是否按设置成功,KEY不存在时会返回false
     */
    public boolean expire(String key, long expireSeconds) {
        key = trimKey(key);
        if (expireSeconds >= 0) {
            return redisTemplate.expire(key, expireSeconds, EXPIRE_TIME_UNIT);
        } else {
            // 移除过期时间
            long oldExpireSeconds = getExpire(key);
            if (oldExpireSeconds <=-2) {
                // KEY不存在
                return false;
            } else if (oldExpireSeconds == -1) {
                // 已经是长期缓存
                return true;
            } else {
                return redisTemplate.persist(key);
            }
        }
    }

    /**
     * 获取过期时间(单位秒),-2表示KEY不存在,-1表示常驻
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key);
    }

    /**
     * 自增,如果不存在KEY,则创建该KEY,值从0开始.步长为1
     * 过期时间不会为常驻,默认使用默认过期时间
     * @param key KEY
     * @return 增长后的值
     */
    public long increment(String key) {
        return increment(key, 1);
    }

    /**
     * 自增,如果不存在KEY,则创建该KEY,值从0开始
     * 过期时间不会为常驻,默认使用默认过期时间
     * @param key KEY
     * @param delta 步长
     * @return 增长后的值
     */
    public long increment(String key, long delta) {
        key = trimKey(key);
        long result = redisTemplate.opsForValue().increment(key, delta);
        if (getExpire(key) == -1) {
            expire(key, DEFAULT_EXPIRE_TIME);
        }
        return result;
    }

    /**
     * 校验KEY不能为空,并去除两边空格
     */
    private String trimKey(String key) {
        key = (key == null ? "" : key.trim());
        if (key.length() == 0) {
            throw new RuntimeException("KEY不能为空");
        }
        return key;
    }

    public void setString(String key, String value) {
        setString(key, value, DEFAULT_EXPIRE_TIME);
    }

    public void setString(String key, String value, long expireSeconds) {
        setObject(key, value, expireSeconds);
    }

    public String getString(String key) {
        return getObject(key, String.class);
    }

    public void setCharacter(String key, Character value) {
        setCharacter(key, value, DEFAULT_EXPIRE_TIME);
    }

    public void setCharacter(String key, Character value, long expireSeconds) {
        setObject(key, value, expireSeconds);
    }

    public Character getCharacter(String key) {
        return getObject(key, Character.class);
    }

    public void setBoolean(String key, Boolean value) {
        setBoolean(key, value, DEFAULT_EXPIRE_TIME);
    }

    public void setBoolean(String key, Boolean value, long expireSeconds) {
        setObject(key, value, expireSeconds);
    }

    public Boolean getBoolean(String key) {
        return getObject(key, Boolean.class);
    }

    public void setByte(String key, Byte value) {
        setByte(key, value, DEFAULT_EXPIRE_TIME);
    }

    public void setByte(String key, Byte value, long expireSeconds) {
        setObject(key, value, expireSeconds);
    }

    public Byte getByte(String key) {
        return getObject(key, Byte.class);
    }

    public void setShort(String key, Short value) {
        setShort(key, value, DEFAULT_EXPIRE_TIME);
    }

    public void setShort(String key, Short value, long expireSeconds) {
        setObject(key, value, expireSeconds);
    }

    public Short getShort(String key) {
        return getObject(key, Short.class);
    }

    public void setInteger(String key, Integer value) {
        setInteger(key, value, DEFAULT_EXPIRE_TIME);
    }

    public void setInteger(String key, Integer value, long expireSeconds) {
        setObject(key, value, expireSeconds);
    }

    public Integer getInteger(String key) {
        return getObject(key, Integer.class);
    }

    public void setLong(String key, Long value) {
        setLong(key, value, DEFAULT_EXPIRE_TIME);
    }

    public void setLong(String key, Long value, long expireSeconds) {
        setObject(key, value, expireSeconds);
    }

    public Long getLong(String key) {
        return getObject(key, Long.class);
    }

    public void setFloat(String key, Float value) {
        setFloat(key, value, DEFAULT_EXPIRE_TIME);
    }

    public void setFloat(String key, Float value, long expireSeconds) {
        setObject(key, value, expireSeconds);
    }

    public Float getFloat(String key) {
        return getObject(key, Float.class);
    }

    public void setDouble(String key, Double value) {
        setDouble(key, value, DEFAULT_EXPIRE_TIME);
    }

    public void setDouble(String key, Double value, long expireSeconds) {
        setObject(key, value, expireSeconds);
    }

    public Double getDouble(String key) {
        return getObject(key, Double.class);
    }
}
